"""
Anthropic Claude API提供商
支持直接访问Anthropic API
"""
import json
import os
import time
import logging
from typing import Dict, List, Optional, Any, Generator
import requests

from ..core.provider import RemoteProvider
from ..core.exceptions import map_provider_error
from ..implementations.anthropic.streaming import AnthropicStreaming
from ..implementations.anthropic.tool_call import AnthropicToolCall
from ..implementations.anthropic.partial_mode import AnthropicPartialMode
from ..core.provider_registry import register_provider

# 设置日志
logger = logging.getLogger("llm.anthropic")

# 尝试导入anthropic库，如果不存在则提供一个后备实现
try:
    import anthropic
    HAS_ANTHROPIC_SDK = True
except ImportError:
    HAS_ANTHROPIC_SDK = False
    logger.warning("未安装anthropic SDK，将使用后备实现")


@register_provider("anthropic")
class AnthropicProvider(RemoteProvider):
    """Anthropic Claude API提供商"""
    
    def __init__(self, config: Dict[str, Any]):
        """
        初始化Anthropic提供商
        
        Args:
            config: 配置字典
        """
        # 初始化工具选项
        self.tools_enabled = config.get("tools", False)
        
        # 确保正确初始化所有父类
        super().__init__(config)
        
        # 初始化特有配置
        self.model = config.get("model", "claude-3-5-sonnet")
        
        # 初始化客户端
        if HAS_ANTHROPIC_SDK:
            self.client = anthropic.Anthropic(api_key=self.api_key)
        else:
            self.client = None
            
        # 验证配置
        self._validate_config(config)
            
    def _validate_config(self, config: Dict[str, Any]) -> None:
        """
        验证配置合法性
        
        Args:
            config: 配置字典
            
        Raises:
            ConfigurationError: 如果配置不合法
        """
        # 已在RemoteProvider中验证API密钥
        
        # 验证模型名称
        if not self.model.startswith("claude-"):
            logger.warning(f"未知的Claude模型: {self.model}，建议使用claude-3系列模型")
            
    def _init_capabilities(self) -> None:
        """初始化Anthropic支持的功能组件"""
        logger.debug("初始化Anthropic功能组件")

        # 添加流式输出功能
        self.register_capability("streaming", AnthropicStreaming)

        # 添加工具调用功能（如果配置中启用）
        if self.tools_enabled:
            self.register_capability("tool_calls", AnthropicToolCall)

        # 添加部分输出功能
        self.register_capability("partial_mode", AnthropicPartialMode)
        
    def get_current_messages(self) -> List[Dict[str, Any]]:
        """
        获取当前会话消息
        用于部分输出模式
        
        Returns:
            消息列表，如果未保持状态则为空列表
        """
        # 基础实现不保持状态，返回空列表
        # 子类可以重写此方法提供会话状态
        return []
        
    def complete(self, messages: List[Dict[str, str]], stream: bool = False) -> str:
        """
        获取LLM完成
        
        Args:
            messages: 消息列表
            stream: 是否使用流式响应
            
        Returns:
            完成的文本
        """
        if stream:
            return "".join([chunk for chunk in self.complete_stream(messages)])
            
        response = self._call_with_retry(self._complete_internal, messages)
        
        # 提取响应文本
        if not isinstance(response, (str, dict)):
            raise Exception(f"无效的API响应: {type(response)}")
            
        # 处理字符串结果
        if isinstance(response, str):
            return response
            
        # 提取思考过程（如果有）
        thinking = self.extract_thinking(response)
        if thinking:
            logger.debug(f"思考过程: {thinking}")
            
        return response
        
    def _prepare_request_params(self, messages: List[Dict[str, Any]], **kwargs) -> Dict[str, Any]:
        """
        准备API请求参数
        
        Args:
            messages: 消息列表
            **kwargs: 额外的提供商特定参数
            
        Returns:
            请求参数字典
        """
        return {
            "model": self.model,
            "messages": messages,
            "max_tokens": self.max_tokens,
            "temperature": self.temperature,
            **kwargs
        }
        
    def _add_tools_to_request(self, params: Dict[str, Any]) -> Dict[str, Any]:
        """
        添加工具功能到请求参数
        
        Args:
            params: 请求参数字典
            
        Returns:
            更新后的请求参数字典
        """
        result = params.copy()
        
        # 添加工具功能（如果可用）
        if self.has_capability("tool_calls"):
            tool_call = self.get_capability("tool_calls")
            result["tools"] = tool_call.format_tools_for_request()
            
            # 设置系统指令使模型积极使用工具
            system_message = "请主动使用提供的工具来更好地完成任务。在不确定的情况下，使用工具获取信息比猜测更好。"
            
            # 添加或更新系统消息
            if "system" in result:
                result["system"] += "\n\n" + system_message
            else:
                result["system"] = system_message
                
        return result
        
    def _handle_tool_calls(self, completion: Any) -> List[Dict[str, Any]]:
        """
        处理工具调用结果
        
        Args:
            completion: API完成响应
            
        Returns:
            工具执行结果列表
        """
        results = []
        
        if not self.has_capability("tool_calls"):
            return results
            
        tool_call_capability = self.get_capability("tool_calls")
        tool_calls = tool_call_capability.detect_tool_calls(completion)
        
        if tool_calls:
            results = tool_call_capability.execute_tool_calls(tool_calls)
            
        return results
        
    def _complete_internal(self, messages: List[Dict[str, Any]], **kwargs) -> str:
        """
        内部完成方法实现
        
        Args:
            messages: 消息列表
            **kwargs: 额外参数
            
        Returns:
            完成的文本
        """
        start_time = time.time()
        
        try:
            # 准备请求参数
            params = self._prepare_request_params(messages, **kwargs)
            
            # 添加工具（如果有）
            if self.tools_enabled:
                params = self._add_tools_to_request(params)
            
            # 选择请求方式
            if HAS_ANTHROPIC_SDK and self.client:
                # 使用官方SDK
                response = self.client.messages.create(**params)
                
                # 解析响应
                if hasattr(response, "content") and len(response.content) > 0:
                    content_item = response.content[0]
                    if hasattr(content_item, "text"):
                        result = content_item.text
                    else:
                        result = getattr(content_item, "text", str(content_item))
                        
                    # 处理工具调用（如果有）
                    if hasattr(response, "stop_reason") and response.stop_reason == "tool_use":
                        tool_results = self._handle_tool_calls(response)
                        if tool_results:
                            # 将工具结果添加到消息并重新调用API
                            new_messages = messages.copy()
                            new_messages.append({"role": "assistant", "content": result})
                            for result_item in tool_results:
                                new_messages.append(result_item)
                            return self._complete_internal(new_messages)
                else:
                    result = str(response)
            else:
                # 后备实现：直接使用API
                headers = {
                    "x-api-key": self.api_key,
                    "anthropic-version": "2023-06-01",
                    "content-type": "application/json"
                }
                
                response = requests.post(
                    "https://api.anthropic.com/v1/messages",
                    headers=headers,
                    json=params,
                    timeout=self.timeout
                )
                
                if response.status_code != 200:
                    raise Exception(f"API请求失败: {response.status_code} {response.text}")
                    
                data = response.json()
                
                if "content" in data and len(data["content"]) > 0:
                    content_item = data["content"][0]
                    result = content_item.get("text", "")
                    
                    # 处理工具调用（如果有）
                    if data.get("stop_reason") == "tool_use":
                        tool_results = self._handle_tool_calls(data)
                        if tool_results:
                            # 将工具结果添加到消息并重新调用API
                            new_messages = messages.copy()
                            new_messages.append({"role": "assistant", "content": result})
                            for result_item in tool_results:
                                new_messages.append(result_item)
                            return self._complete_internal(new_messages)
                else:
                    result = "未收到有效响应内容"
                
            elapsed = time.time() - start_time
            logger.info(f"Anthropic请求完成，耗时: {elapsed:.2f}秒，模型: {self.model}")
            
            return result
        except Exception as e:
            elapsed = time.time() - start_time
            logger.error(f"Anthropic请求失败，耗时: {elapsed:.2f}秒，错误: {str(e)}")
            
            # 映射错误为标准LLM异常
            mapped_error = map_provider_error("anthropic", e, self.model)
            raise mapped_error
            
    def complete_stream(self, messages: List[Dict[str, str]]) -> Generator[str, None, None]:
        """
        获取LLM流式完成
        
        Args:
            messages: 消息列表
            
        Returns:
            流式响应生成器
        """
        # 检查是否支持流式输出
        if not self.has_capability("streaming"):
            # 如果不支持流式输出，使用标准完成方法并逐字符生成
            content = self._complete_internal(messages)
            for char in content:
                yield char
            return
            
        # 使用流式输出能力组件
        streaming = self.get_capability("streaming")
        yield from streaming.stream_response(messages)
